#    pythonequations is a collection of equations expressed as Python classes
#    Copyright (C) 2008 James R. Phillips
#    2548 Vera Cruz Drive
#    Birmingham, AL 35235 USA
#    email: zunzun@zunzun.com
#
#    License: BSD-style (see LICENSE.txt in main source directory)
#    Version info: $Id: Polynomial.py 282 2010-12-11 14:01:16Z zunzun.com $

import pythonequations, pythonequations.EquationBaseClasses, pythonequations.ExtraCodeForEquationBaseClasses
import numpy
numpy.seterr(all = 'raise') # numpy raises warnings, convert to exceptions to trap them


class MarcPlanteQuadratic2D(pythonequations.EquationBaseClasses.Equation2D):
    RequiresAutoGeneratedGrowthAndDecayForms = True
    RequiresAutoGeneratedOffsetForm = True
    RequiresAutoGeneratedReciprocalForm = False
    RequiresAutoGeneratedInverseForms = False
    _name = "Marc Plante's Custom Quadratic"
    _HTML = "y = (-b + (b<sup>2</sup> - 4 a (c - x))<sup>0.5</sup>) / 2 / a "
    coefficientDesignatorTuple = ("a", "b", "c")
    function_cpp_code = 'temp = ((-1.0 * coeff[1]) + pow((coeff[1] * coeff[1]) - 4.0 * coeff[0] * (coeff[2] - _id[_cwo[0]+i]), 0.5)) / 2.0 / coeff[0];'


    def CreateCacheGenerationList(self):
        self.CacheGenerationList = []
        self.CacheGenerationList.append([pythonequations.ExtraCodeForEquationBaseClasses.CG_X(NameOrValueFlag=1), []])

    def SpecificCodeCPP(self):
        s = "\ttemp += ((-1.0 * b) + pow((b * b) - 4.0 * a * (c - x_in), 0.5)) / 2.0 / a;\n"
        return s



class Linear2D(pythonequations.EquationBaseClasses.Equation2D):
    RequiresAutoGeneratedGrowthAndDecayForms = True
    RequiresAutoGeneratedOffsetForm = False
    RequiresAutoGeneratedReciprocalForm = True
    RequiresAutoGeneratedInverseForms = True
    _name = "Linear"
    _HTML = "y = a + bx"
    coefficientDesignatorTuple = ("a", "b")
    LinearSSQSolverFlag = 1
    function_cpp_code = 'temp = coeff[0] + (coeff[1] * _id[_cwo[1]+i]);'


    def CreateCacheGenerationList(self):
        self.CacheGenerationList = []
        self.CacheGenerationList.append([pythonequations.ExtraCodeForEquationBaseClasses.CG_Ones(NameOrValueFlag=1), []])
        self.CacheGenerationList.append([pythonequations.ExtraCodeForEquationBaseClasses.CG_X(NameOrValueFlag=1), []])

    def SpecificCodeCPP(self):
        s = "\ttemp += " + self.coefficientDesignatorTuple[0] + " + " + self.coefficientDesignatorTuple[1] + " * x_in;\n"
        return s



class Quadratic2D(pythonequations.EquationBaseClasses.Equation2D):
    RequiresAutoGeneratedGrowthAndDecayForms = True
    RequiresAutoGeneratedOffsetForm = False
    RequiresAutoGeneratedReciprocalForm = True
    RequiresAutoGeneratedInverseForms = True
    _name = "Quadratic"
    _HTML = "y = a + bx + cx<SUP>2</SUP>"
    coefficientDesignatorTuple = ("a", "b", "c")
    LinearSSQSolverFlag = 1
    function_cpp_code = 'temp = coeff[0] + coeff[1] * _id[_cwo[1]+i] + coeff[2] * _id[_cwo[2]+i];'


    def CreateCacheGenerationList(self):
        self.CacheGenerationList = []
        self.CacheGenerationList.append([pythonequations.ExtraCodeForEquationBaseClasses.CG_Ones(NameOrValueFlag=1), []])
        self.CacheGenerationList.append([pythonequations.ExtraCodeForEquationBaseClasses.CG_X(NameOrValueFlag=1),  []])
        self.CacheGenerationList.append([pythonequations.ExtraCodeForEquationBaseClasses.CG_PowX(NameOrValueFlag=1, args=[2.0]), [2.0]])

    def SpecificCodeCPP(self):
        s = "\ttemp += " + self.coefficientDesignatorTuple[0] + ";\n"
        s += "\ttemp += " + self.coefficientDesignatorTuple[1] + " * x_in;\n"
        s += "\ttemp += " + self.coefficientDesignatorTuple[2] + " * pow(x_in, 2.0);\n"
        return s



class Cubic2D(pythonequations.EquationBaseClasses.Equation2D):
    RequiresAutoGeneratedGrowthAndDecayForms = True
    RequiresAutoGeneratedOffsetForm = False
    RequiresAutoGeneratedReciprocalForm = True
    RequiresAutoGeneratedInverseForms = True
    _name = "Cubic"
    _HTML = "y = a + bx + cx<SUP>2</SUP> + dx<SUP>3</SUP>"
    coefficientDesignatorTuple = ("a", "b", "c", "d")
    LinearSSQSolverFlag = 1
    function_cpp_code = 'temp = coeff[0] + coeff[1] * _id[_cwo[1]+i] + coeff[2] * _id[_cwo[2]+i] + coeff[3] * _id[_cwo[3]+i];'


    def CreateCacheGenerationList(self):
        self.CacheGenerationList = []
        self.CacheGenerationList.append([pythonequations.ExtraCodeForEquationBaseClasses.CG_Ones(NameOrValueFlag=1), []])
        self.CacheGenerationList.append([pythonequations.ExtraCodeForEquationBaseClasses.CG_X(NameOrValueFlag=1), []])
        self.CacheGenerationList.append([pythonequations.ExtraCodeForEquationBaseClasses.CG_PowX(NameOrValueFlag=1, args=[2.0]), [2.0]])
        self.CacheGenerationList.append([pythonequations.ExtraCodeForEquationBaseClasses.CG_PowX(NameOrValueFlag=1, args=[3.0]), [3.0]])

    def SpecificCodeCPP(self):
        s = "\ttemp += " + self.coefficientDesignatorTuple[0] + ";\n"
        s += "\ttemp += " + self.coefficientDesignatorTuple[1] + " * x_in;\n"
        s += "\ttemp += " + self.coefficientDesignatorTuple[2] + " * pow(x_in, 2.0);\n"
        s += "\ttemp += " + self.coefficientDesignatorTuple[3] + " * pow(x_in, 3.0);\n"
        return s



class Polynomial2D(pythonequations.EquationBaseClasses.Equation2D):
    RequiresAutoGeneratedGrowthAndDecayForms = False
    RequiresAutoGeneratedOffsetForm = False
    RequiresAutoGeneratedReciprocalForm = True
    RequiresAutoGeneratedInverseForms = True
    _name = "User-Selectable Polynomial"
    _HTML = "y = a + bx + cx<SUP>2</SUP> + dx<SUP>3</SUP> + ..."
    coefficientDesignatorTuple = ()
    polynomialFlag = 1
    LinearSSQSolverFlag = 1
    function_cpp_code = 'temp = 0.0;\nfor (int k=0; k<_nc; k++)\n\ttemp += coeff[k] * _id[_cwo[k]+i];'


    def CreateCacheGenerationList(self):
        self.CacheGenerationList = []
        for i in range(self.xPolynomialOrder+1): # 0 - xOrder
            self.CacheGenerationList.append([pythonequations.ExtraCodeForEquationBaseClasses.CG_PowX(NameOrValueFlag=1, args=[float(i)]), [float(i)]])
 
 
    def SpecificCodeCPP(self):
        s = ""
        length = len(self.coefficientArray)
        for i in range(length-1, -1, -1):
            if i == length-1:
                s += "\ttemp = " + self.coefficientDesignatorTuple[i] + ";\n"
            else:
                s += "\ttemp = temp * x_in + " + self.coefficientDesignatorTuple[i] + ";\n"
        return s


    def Initialize(self):
                
        self.coefficientDesignatorTuple = ()

        self._HTML = "y = "
        for i in range(self.xPolynomialOrder+1): # 0 - xOrder
            self.coefficientDesignatorTuple += (pythonequations.EquationBaseClasses.Equation.ascii[i]),
            if i == 0:
                self._HTML += pythonequations.EquationBaseClasses.Equation.ascii[i]
            else:
                self._HTML += pythonequations.EquationBaseClasses.Equation.ascii[i] + 'x<SUP>' + str(i) + '</SUP>'
            if i != self.xPolynomialOrder:
                self._HTML += ' + '

        pythonequations.EquationBaseClasses.Equation2D.Initialize(self)
